home *** CD-ROM | disk | FTP | other *** search
/ Micromanía 92 / CDMM92_1.ISO / SOF 2 SDK / sof2sdk-101.msi / _92D6AC311BB48EBA344BBABC89DA6AB0 / _80CF4A34DD9E4405821C2BA3955ABF80 < prev    next >
Encoding:
Text File  |  2002-07-01  |  42.1 KB  |  1,804 lines

  1. // Copyright (C) 2001-2002 Raven Software.
  2. //
  3.  
  4. #include "g_local.h"
  5.  
  6. level_locals_t    level;
  7.  
  8. typedef struct 
  9. {
  10.     vmCvar_t    *vmCvar;
  11.     char        *cvarName;
  12.     char        *defaultString;
  13.     int            cvarFlags;
  14.     float        mMinValue, mMaxValue;
  15.     int            modificationCount;  // for tracking changes
  16.     qboolean    trackChange;        // track this variable, and announce if changed
  17.     qboolean    teamShader;            // track and if changed, update shader state
  18.  
  19. } cvarTable_t;
  20.  
  21. gentity_t        g_entities[MAX_GENTITIES];
  22. gclient_t        g_clients[MAX_CLIENTS];
  23.  
  24. vmCvar_t    g_gametype;
  25. vmCvar_t    g_dmflags;
  26. vmCvar_t    g_scorelimit;
  27. vmCvar_t    g_timelimit;
  28. vmCvar_t    g_friendlyFire;
  29. vmCvar_t    g_password;
  30. vmCvar_t    g_needpass;
  31. vmCvar_t    g_maxclients;
  32. vmCvar_t    g_maxGameClients;
  33. vmCvar_t    g_dedicated;
  34. vmCvar_t    g_speed;
  35. vmCvar_t    g_gravity;
  36. vmCvar_t    g_cheats;
  37. vmCvar_t    g_knockback;
  38. vmCvar_t    g_forcerespawn;
  39. vmCvar_t    g_inactivity;
  40. vmCvar_t    g_debugMove;
  41. vmCvar_t    g_debugDamage;
  42. vmCvar_t    g_debugAlloc;
  43. vmCvar_t    g_weaponRespawn;
  44. vmCvar_t    g_backpackRespawn;
  45. vmCvar_t    g_motd;
  46. vmCvar_t    g_synchronousClients;
  47. vmCvar_t    g_warmup;
  48. vmCvar_t    g_doWarmup;
  49. vmCvar_t    g_restarted;
  50. vmCvar_t    g_log;
  51. vmCvar_t    g_logSync;
  52. vmCvar_t    g_logHits;
  53. vmCvar_t    g_allowVote;
  54. vmCvar_t    g_voteDuration;
  55. vmCvar_t    g_voteKickBanTime;
  56. vmCvar_t    g_failedVoteDelay;
  57. vmCvar_t    g_teamAutoJoin;
  58. vmCvar_t    g_teamForceBalance;
  59. vmCvar_t    g_smoothClients;
  60. vmCvar_t    pmove_fixed;
  61. vmCvar_t    pmove_msec;
  62. vmCvar_t    g_rankings;
  63. vmCvar_t    g_listEntity;
  64. vmCvar_t    g_fps;
  65. vmCvar_t    g_respawnInterval;
  66. vmCvar_t    g_respawnInvulnerability;
  67. vmCvar_t    g_roundtimelimit;
  68. vmCvar_t    g_roundjointime;
  69. vmCvar_t    g_timeextension;
  70. vmCvar_t    g_timeouttospec;
  71. vmCvar_t    g_roundstartdelay;
  72. vmCvar_t    g_availableWeapons;
  73. vmCvar_t    g_forceFollow;
  74. vmCvar_t    g_followEnemy;
  75. vmCvar_t    g_mapcycle;
  76. vmCvar_t    g_pickupsDisabled;                // Whether or not pickups are available in a map (uses outfitting if not)
  77. vmCvar_t    g_suicidePenalty;                // Amount of score added for killing yourself (typically negative)
  78. vmCvar_t    g_teamkillPenalty;                // Amount of score added for killing a teammates (typically negative)
  79. vmCvar_t    g_teamkillDamageMax;            // max damage one can do to teammates before being kicked
  80. vmCvar_t    g_teamkillDamageForgive;        // amount of teamkill damage forgiven each minute
  81. vmCvar_t    g_teamkillBanTime;                // number of minutes to ban someone for after being kicked 
  82. vmCvar_t    g_voiceFloodCount;                // Number of voice messages in one minute to be concidered flooding
  83. vmCvar_t    g_voiceFloodPenalty;            // Amount of time a void flooder must wait before they can use voice again
  84. vmCvar_t    g_suddenDeath;
  85. vmCvar_t    g_voiceTalkingGhosts;            // Allow ghosts to talk to alive players
  86.  
  87. vmCvar_t    RMG;
  88. vmCvar_t    g_debugRMG;
  89.  
  90. static cvarTable_t gameCvarTable[] = 
  91. {
  92.     // don't override the cheat state set by the system
  93.     { &g_cheats, "sv_cheats", "", 0, 0.0, 0.0, 0, qfalse },
  94.  
  95.     // noset vars
  96.     { NULL, "gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_ROM, 0.0, 0.0, 0, qfalse  },
  97.     { NULL, "gamedate", __DATE__ , CVAR_ROM, 0.0, 0.0, 0, qfalse  },
  98.     { &g_restarted, "g_restarted", "0", CVAR_ROM, 0.0, 0.0, 0, qfalse  },
  99.     { NULL, "sv_mapname", "", CVAR_SERVERINFO | CVAR_ROM, 0.0, 0.0, 0, qfalse  },
  100.  
  101.     { &g_fps, "sv_fps", "", CVAR_ROM, 0.0, 0.0, 0, qfalse },
  102.  
  103.     // latched vars
  104.     { &g_gametype, "g_gametype", "dm", CVAR_SERVERINFO | CVAR_LATCH, 0.0, 0.0, 0, qfalse  },
  105.  
  106.     { &g_maxclients, "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse  },
  107.     { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse  },
  108.  
  109.     { &g_dmflags, "dmflags", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0.0, 0.0, 0, qtrue  },
  110.     { &g_scorelimit, "scorelimit", "20", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0.0, 0.0, 0, qtrue },
  111.     { &g_timelimit, "timelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0.0, 0.0, 0, qtrue },
  112.  
  113.     { &g_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO, 0.0, 0.0, 0, qfalse  },
  114.  
  115.     { &g_friendlyFire, "g_friendlyFire", "0", CVAR_SERVERINFO|CVAR_ARCHIVE, 0.0, 0.0, 0, qtrue  },
  116.  
  117.     { &g_teamAutoJoin, "g_teamAutoJoin", "0", CVAR_ARCHIVE, 0.0, 0.0,   },
  118.     { &g_teamForceBalance, "g_teamForceBalance", "0", CVAR_ARCHIVE, 0.0, 0.0,   },
  119.  
  120.     { &g_warmup, "g_warmup", "20", CVAR_ARCHIVE, 0.0, 0.0, 0, qtrue  },
  121.     { &g_doWarmup, "g_doWarmup", "0", 0, 0.0, 0.0, 0, qtrue  },
  122.     { &g_log, "g_log", "games.log", CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse  },
  123.     { &g_logSync, "g_logSync", "0", CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse  },
  124.     { &g_logHits, "g_logHits", "0", CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse  },
  125.  
  126.     { &g_password, "g_password", "", CVAR_USERINFO, 0.0, 0.0, 0, qfalse  },
  127.  
  128.     { &g_needpass, "g_needpass", "0", CVAR_SERVERINFO | CVAR_ROM, 0.0, 0.0, 0, qfalse },
  129.  
  130.     { &g_dedicated, "dedicated", "0", 0, 0.0, 0.0, 0, qfalse  },
  131.  
  132.     { &g_speed, "g_speed", "280", 0, 0.0, 0.0, 0, qtrue  },
  133.     { &g_gravity, "g_gravity", "800", 0, 0.0, 0.0, 0, qtrue  },
  134.     { &g_knockback, "g_knockback", "700", 0, 0.0, 0.0, 0, qtrue  },
  135.     { &g_weaponRespawn, "g_weaponrespawn", "15", 0, 0.0, 0.0, 0, qtrue  },
  136.     { &g_backpackRespawn, "g_backpackrespawn", "40", 0, 0.0, 0.0, 0, qtrue  },
  137.     { &g_forcerespawn, "g_forcerespawn", "20", 0, 0.0, 0.0, 0, qtrue },
  138.     { &g_inactivity, "g_inactivity", "180", CVAR_ARCHIVE, 0.0, 0.0, 0, qtrue },
  139.     { &g_debugMove, "g_debugMove", "0", 0, 0.0, 0.0, 0, qfalse },
  140.     { &g_debugDamage, "g_debugDamage", "0", 0, 0.0, 0.0, 0, qfalse },
  141.     { &g_debugAlloc, "g_debugAlloc", "0", 0, 0.0, 0.0, 0, qfalse },
  142.     { &g_motd, "g_motd", "", 0, 0.0, 0.0, 0, qfalse },
  143.  
  144.     { &g_allowVote, "g_allowVote", "1", CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  145.     { &g_voteDuration, "g_voteDuration", "60", CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  146.     { &g_voteKickBanTime, "g_voteKickBanTime", "0", CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  147.     { &g_failedVoteDelay, "g_failedVoteDelay", "1", CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  148.     { &g_listEntity, "g_listEntity", "0", 0, 0.0, 0.0, 0, qfalse },
  149.  
  150.     { &g_smoothClients, "g_smoothClients", "1", 0, 0.0, 0.0, 0, qfalse},
  151.     { &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO, 0.0, 0.0, 0, qfalse},
  152.     { &pmove_msec, "pmove_msec", "8", CVAR_SYSTEMINFO, 0.0, 0.0, 0, qfalse},
  153.  
  154.     { &g_rankings, "g_rankings", "0", 0, 0.0, 0.0, 0, qfalse},
  155.  
  156.     { &g_respawnInterval, "g_respawnInterval", "15", CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  157.     { &g_respawnInvulnerability, "g_respawnInvulnerability", "5", CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  158.  
  159.     { &RMG, "RMG", "0", 0, 0.0, 0.0, },
  160.     { &g_debugRMG, "g_debugRMG", "0", 0, 0.0f, 0.0f },
  161.  
  162.     { &g_timeouttospec,        "g_timeouttospec",    "15",        CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  163.     { &g_roundtimelimit,    "g_roundtimelimit",    "5",        CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  164.     { &g_roundjointime,        "g_roundjointime",    "5",        CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  165.     { &g_timeextension,        "g_timeextension",    "15",        CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  166.  
  167.     { &g_roundstartdelay,    "g_roundstartdelay", "5",        CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  168.  
  169.     { &g_availableWeapons,    "g_availableWeapons", "22222222222211", CVAR_ARCHIVE|CVAR_SERVERINFO|CVAR_LATCH, 0.0, 0.0, 0, qfalse },
  170.  
  171.     { &g_forceFollow,        "g_forceFollow",     "0",              CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  172.     { &g_followEnemy,        "g_followEnemy",     "1",              CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  173.  
  174.     { &g_mapcycle,            "sv_mapcycle",         "none",        CVAR_ARCHIVE, 0.0, 0.0, 0, qfalse },
  175.  
  176.     { &g_pickupsDisabled,    "g_pickupsDisabled", "0",                    CVAR_ARCHIVE|CVAR_LATCH, 0.0, 0.0, 0, qfalse },
  177.  
  178.     { &g_suicidePenalty,    "g_suicidePenalty",  "-1",                    CVAR_ARCHIVE,    0.0f,    0.0f,    0,    qfalse },
  179.  
  180.     { &g_voiceFloodCount,    "g_voiceFloodCount",    "6",                CVAR_ARCHIVE,    0.0f,    0.0f,    0,  qfalse },
  181.     { &g_voiceFloodPenalty,    "g_voiceFloodPenalty",    "60",                CVAR_ARCHIVE,    0.0f,    0.0f,    0,  qfalse },
  182.  
  183.     { &g_teamkillPenalty,        "g_teamkillPenalty",        "-1",        CVAR_ARCHIVE,    0.0f,    0.0f,    0,    qfalse },
  184.     { &g_teamkillDamageMax,        "g_teamkillDamageMax",        "300",        CVAR_ARCHIVE,    0.0f,    0.0f,    0,  qfalse },
  185.     { &g_teamkillDamageForgive,    "g_teamkillDamageForgive",    "50",        CVAR_ARCHIVE,    0.0f,    0.0f,    0,  qfalse },
  186.     { &g_teamkillBanTime,        "g_teamkillBanTime",        "5",        CVAR_ARCHIVE,   0.0f,    0.0f,    0,  qfalse },
  187.  
  188.     { &g_suddenDeath,            "g_suddenDeath",            "1",        CVAR_ARCHIVE,    0.0f,    0.0f,    0,  qfalse },
  189.  
  190.     { &g_voiceTalkingGhosts,    "g_voiceTalkingGhosts",        "1",        CVAR_ARCHIVE,    0.0f,    0.0f,    0,  qfalse },
  191. };
  192.  
  193. // bk001129 - made static to avoid aliasing
  194. static int gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[0] );
  195.  
  196.  
  197. void G_InitGame                    ( int levelTime, int randomSeed, int restart );
  198. void G_RunFrame                    ( int levelTime );
  199. void G_ShutdownGame                ( int restart );
  200. void CheckExitRules                ( void );
  201. void G_InitGhoul                ( void );
  202. void G_ShutdownGhoul            ( void );
  203.  
  204. /*
  205. ================
  206. vmMain
  207.  
  208. This is the only way control passes into the module.
  209. This must be the very first function compiled into the .q3vm file
  210. ================
  211. */
  212. int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11  ) 
  213. {
  214.     switch ( command ) 
  215.     {
  216.         case GAME_GHOUL_INIT:
  217.             G_InitGhoul ( );
  218.             return 0;
  219.         case GAME_GHOUL_SHUTDOWN:
  220.             G_ShutdownGhoul ( );
  221.             return 0;
  222.         case GAME_INIT:
  223.             G_InitGame( arg0, arg1, arg2 );
  224.             return 0;
  225.         case GAME_SHUTDOWN:
  226.             G_ShutdownGame( arg0 );
  227.             return 0;
  228.         case GAME_CLIENT_CONNECT:
  229.             return (int)ClientConnect( arg0, arg1, arg2 );
  230.         case GAME_CLIENT_THINK:
  231.             ClientThink( arg0 );
  232.             return 0;
  233.         case GAME_CLIENT_USERINFO_CHANGED:
  234.             ClientUserinfoChanged( arg0 );
  235.             return 0;
  236.         case GAME_CLIENT_DISCONNECT:
  237.             ClientDisconnect( arg0 );
  238.             return 0;
  239.         case GAME_CLIENT_BEGIN:
  240.             ClientBegin( arg0 );
  241.             return 0;
  242.         case GAME_CLIENT_COMMAND:
  243.             ClientCommand( arg0 );
  244.             return 0;
  245.         case GAME_GAMETYPE_COMMAND:
  246.             return G_GametypeCommand ( arg0, arg1, arg2, arg3, arg4, arg5 );
  247.         case GAME_RUN_FRAME:
  248.             G_RunFrame( arg0 );
  249.             return 0;
  250.         case GAME_CONSOLE_COMMAND:
  251.             return ConsoleCommand();
  252.         case BOTAI_START_FRAME:
  253.             return BotAIStartFrame( arg0 );
  254.         case GAME_SPAWN_RMG_ENTITY:
  255.             if (G_ParseSpawnVars(qfalse))
  256.             {
  257.                 G_SpawnGEntityFromSpawnVars(qfalse);
  258.             }
  259.             return 0;
  260.     }
  261.  
  262.     return -1;
  263. }
  264.  
  265. /*
  266. ================
  267. G_FindTeams
  268.  
  269. Chain together all entities with a matching team field.
  270. Entity teams are used for item groups and multi-entity mover groups.
  271.  
  272. All but the first will have the FL_TEAMSLAVE flag set and teammaster field set
  273. All but the last will have the teamchain field set to the next one
  274. ================
  275. */
  276. void G_FindTeams( void ) {
  277.     gentity_t    *e, *e2;
  278.     int        i, j;
  279.     int        c, c2;
  280.  
  281.     c = 0;
  282.     c2 = 0;
  283.     for ( i=1, e=g_entities+i ; i < level.num_entities ; i++,e++ ){
  284.         if (!e->inuse)
  285.             continue;
  286.         if (!e->team)
  287.             continue;
  288.         if (e->flags & FL_TEAMSLAVE)
  289.             continue;
  290.         e->teammaster = e;
  291.         c++;
  292.         c2++;
  293.         for (j=i+1, e2=e+1 ; j < level.num_entities ; j++,e2++)
  294.         {
  295.             if (!e2->inuse)
  296.                 continue;
  297.             if (!e2->team)
  298.                 continue;
  299.             if (e2->flags & FL_TEAMSLAVE)
  300.                 continue;
  301.             if (!strcmp(e->team, e2->team))
  302.             {
  303.                 c2++;
  304.                 e2->teamchain = e->teamchain;
  305.                 e->teamchain = e2;
  306.                 e2->teammaster = e;
  307.                 e2->flags |= FL_TEAMSLAVE;
  308.  
  309.                 // make sure that targets only point at the master
  310.                 if ( e2->targetname ) {
  311.                     e->targetname = e2->targetname;
  312.                     e2->targetname = NULL;
  313.                 }
  314.             }
  315.         }
  316.     }
  317.  
  318.     Com_Printf ("%i teams with %i entities\n", c, c2);
  319. }
  320.  
  321. /*
  322. =================
  323. G_RemapTeamShaders
  324. =================
  325. */
  326. void G_RemapTeamShaders(void) 
  327. {
  328.     trap_SetConfigstring(CS_SHADERSTATE, BuildShaderStateConfig());
  329. }
  330.  
  331. /*
  332. =================
  333. G_RegisterCvars
  334. =================
  335. */
  336. void G_RegisterCvars( void ) 
  337. {
  338.     int            i;
  339.     cvarTable_t    *cv;
  340.     qboolean    remapped = qfalse;
  341.  
  342.     for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) 
  343.     {
  344.         trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags, cv->mMinValue, cv->mMaxValue );
  345.         
  346.         if ( cv->vmCvar )
  347.         {
  348.             cv->modificationCount = cv->vmCvar->modificationCount;
  349.         }
  350.  
  351.         if (cv->teamShader) 
  352.         {
  353.             remapped = qtrue;
  354.         }
  355.     }
  356.  
  357.     if (remapped) 
  358.     {
  359.         G_RemapTeamShaders();
  360.     }
  361.  
  362.     level.warmupModificationCount = g_warmup.modificationCount;
  363. }
  364.  
  365. /*
  366. =================
  367. G_UpdateCvars
  368. =================
  369. */
  370. void G_UpdateCvars( void ) 
  371. {
  372.     int            i;
  373.     cvarTable_t    *cv;
  374.     qboolean    remapped = qfalse;
  375.  
  376.     for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ ) 
  377.     {
  378.         if ( cv->vmCvar ) 
  379.         {
  380.             trap_Cvar_Update( cv->vmCvar );
  381.  
  382.             if ( cv->modificationCount != cv->vmCvar->modificationCount ) 
  383.             {
  384.                 // Handle any modified cvar checks
  385.                 if ( !Q_stricmp ( cv->cvarName, "sv_fps" ) )
  386.                 {
  387.                     if ( cv->vmCvar->integer > 50 )
  388.                     {
  389.                         trap_Cvar_Set ( "sv_fps", "50" );
  390.                         trap_Cvar_Update ( cv->vmCvar );
  391.                     }
  392.                     else if ( cv->vmCvar->integer < 10 )
  393.                     {
  394.                         trap_Cvar_Set ( "sv_fps", "10" );
  395.                         trap_Cvar_Update ( cv->vmCvar );
  396.                     }
  397.                 }                        
  398.  
  399.                 cv->modificationCount = cv->vmCvar->modificationCount;
  400.  
  401.                 if ( cv->trackChange ) 
  402.                 {
  403.                     trap_SendServerCommand( -1, va("print \"Server: %s changed to %s\n\"", cv->cvarName, cv->vmCvar->string ) );
  404.                 }
  405.  
  406.                 if (cv->teamShader) 
  407.                 {
  408.                     remapped = qtrue;
  409.                 }
  410.             }
  411.         }
  412.     }
  413.  
  414.     if (remapped) 
  415.     {
  416.         G_RemapTeamShaders();
  417.     }
  418. }
  419.  
  420. /*
  421. ===============
  422. G_SetGametype
  423.  
  424. Sets the current gametype to the given value, if the map doesnt support it then it will
  425. use the first gametype that it does support
  426. ===============
  427. */
  428. void G_SetGametype ( const char* gametype )
  429. {    
  430.     // Make sure the gametype is valid, if not default to deathmatch
  431.     level.gametype = BG_FindGametype ( gametype );
  432.  
  433.     // First make sure its supported on this map
  434.     if ( !G_DoesMapSupportGametype ( gametype ) || level.gametype == -1 )
  435.     {
  436.         int i = 0;
  437.         
  438.         // Find a gametype it does support
  439.         for ( i = 0; i < bg_gametypeCount; i ++ )
  440.         {
  441.             if ( G_DoesMapSupportGametype ( bg_gametypeData[i].name ) )
  442.             {
  443.                 break;
  444.             }
  445.         }
  446.  
  447.         // This is bad, this means the map doesnt support any gametypes
  448.         if ( i >= bg_gametypeCount )
  449.         {
  450.             Com_Error ( ERR_FATAL, "map does not support any of the available gametypes" );
  451.         }
  452.  
  453.         G_LogPrintf ( "gametype '%s' is not supported on this map and was defaulted to '%s'\n", 
  454.                      gametype,
  455.                      bg_gametypeData[i].name );
  456.  
  457.         gametype = bg_gametypeData[i].name;
  458.         trap_Cvar_Set( "g_gametype", gametype );
  459.         trap_Cvar_Set( "RMG_mission", gametype );
  460.         level.gametype = BG_FindGametype ( gametype );
  461.  
  462.         trap_Cvar_Update( &g_gametype );
  463.     }
  464.  
  465.     level.gametypeData = &bg_gametypeData[level.gametype];    
  466.  
  467.     // Copy the backpack percentage over
  468.     bg_itemlist[MODELINDEX_BACKPACK].quantity = level.gametypeData->backpack;
  469.  
  470.     // Set the pickup state
  471.     if ( RMG.integer || g_pickupsDisabled.integer || level.gametypeData->pickupsDisabled )
  472.     {
  473.         level.pickupsDisabled = qtrue;
  474.         trap_SetConfigstring ( CS_PICKUPSDISABLED, "1" );
  475.     }
  476.     else
  477.     {
  478.         level.pickupsDisabled = qfalse;
  479.         trap_SetConfigstring ( CS_PICKUPSDISABLED, "0" );
  480.     }
  481. }
  482.  
  483. /*
  484. ============
  485. G_InitGame
  486. ============
  487. */
  488. void G_InitGame( int levelTime, int randomSeed, int restart ) 
  489. {
  490.     int    i;
  491.  
  492.     Com_Printf ("------- Game Initialization -------\n");
  493.     Com_Printf ("gamename: %s\n", GAMEVERSION);
  494.     Com_Printf ("gamedate: %s\n", __DATE__);
  495.  
  496.     srand( randomSeed );
  497.  
  498.     // set some level globals
  499.     memset( &level, 0, sizeof( level ) );
  500.     level.time = levelTime;
  501.     level.startTime = levelTime;
  502.  
  503.     G_RegisterCvars();
  504.  
  505.  
  506.     // Load the list of arenas
  507.     G_LoadArenas ( );
  508.  
  509.     // Build the gametype list so we can verify the given gametype
  510.     BG_BuildGametypeList ( );
  511.  
  512.     // Set the current gametype
  513.     G_SetGametype(g_gametype.string);
  514.  
  515.     // Set the available outfitting
  516.     BG_SetAvailableOutfitting ( g_availableWeapons.string );
  517.  
  518.     // Give the game a uniqe id
  519.     trap_SetConfigstring ( CS_GAME_ID, va("%d", randomSeed ) );
  520.  
  521.     if ( g_log.string[0] ) 
  522.     {
  523.         if ( g_logSync.integer ) 
  524.         {
  525.             trap_FS_FOpenFile( g_log.string, &level.logFile, FS_APPEND_SYNC_TEXT );
  526.         } 
  527.         else 
  528.         {
  529.             trap_FS_FOpenFile( g_log.string, &level.logFile, FS_APPEND_TEXT );
  530.         }
  531.         
  532.         if ( !level.logFile ) 
  533.         {
  534.             Com_Printf( "WARNING: Couldn't open logfile: %s\n", g_log.string );
  535.         } 
  536.         else 
  537.         {
  538.             char    serverinfo[MAX_INFO_STRING];
  539.  
  540.             trap_GetServerinfo( serverinfo, sizeof( serverinfo ) );
  541.  
  542.             G_LogPrintf("------------------------------------------------------------\n" );
  543.             G_LogPrintf("InitGame: %s\n", serverinfo );
  544.         }
  545.     } 
  546.     else 
  547.     {
  548.         Com_Printf( "Not logging to disk.\n" );
  549.     }
  550.  
  551.     G_InitWorldSession();
  552.  
  553.     // initialize all entities for this game
  554.     memset( g_entities, 0, MAX_GENTITIES * sizeof(g_entities[0]) );
  555.     level.gentities = g_entities;
  556.  
  557.     // initialize all clients for this game
  558.     level.maxclients = g_maxclients.integer;
  559.     memset( g_clients, 0, MAX_CLIENTS * sizeof(g_clients[0]) );
  560.     level.clients = g_clients;
  561.  
  562.     // set client fields on player ents
  563.     for ( i=0 ; i<level.maxclients ; i++ ) 
  564.     {
  565.         g_entities[i].client = level.clients + i;
  566.     }
  567.  
  568.     // always leave room for the max number of clients,
  569.     // even if they aren't all used, so numbers inside that
  570.     // range are NEVER anything but clients
  571.     level.num_entities = MAX_CLIENTS;
  572.  
  573.     // let the server system know where the entites are
  574.     trap_LocateGameData( level.gentities, 
  575.                          level.num_entities, 
  576.                          sizeof( gentity_t ), 
  577.                          &level.clients[0].ps, 
  578.                          sizeof( level.clients[0] ) );
  579.  
  580.     // Get the boundaries of the world
  581.     trap_GetWorldBounds ( level.worldMins, level.worldMaxs );
  582.  
  583.     // reserve some spots for dead player bodies
  584.     G_InitBodyQueue();
  585.  
  586.     ClearRegisteredItems();
  587.  
  588.     // parse the key/value pairs and spawn gentities
  589.     G_SpawnEntitiesFromString(qfalse);
  590.  
  591.     // Now parse the gametype information that we need.  This needs to be
  592.     // done after the entity spawn so that the items and triggers can be 
  593.     // linked up properly
  594.     G_ParseGametypeFile ( );
  595.  
  596.     BG_ParseInviewFile( level.pickupsDisabled );
  597.  
  598.     // Load in the identities
  599.     BG_ParseNPCFiles ( );
  600.  
  601.     // general initialization
  602.     G_FindTeams();
  603.  
  604.     SaveRegisteredItems();
  605.  
  606.     Com_Printf ("-----------------------------------\n");
  607.  
  608.     if( trap_Cvar_VariableIntegerValue( "com_buildScript" ) ) 
  609.     {
  610.         G_SoundIndex( "sound/player/gurp1.wav" );
  611.         G_SoundIndex( "sound/player/gurp2.wav" );
  612.     }
  613.  
  614. #ifdef _SOF2_BOTS
  615.     if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) 
  616.     {
  617.         BotAISetup( restart );
  618.         BotAILoadMap( restart );
  619.         G_InitBots( restart );
  620.     }
  621. #endif
  622.  
  623.     G_RemapTeamShaders();
  624.  
  625.     // Initialize the gametype 
  626.     trap_GT_Init ( g_gametype.string, restart );
  627.  
  628.     // Music
  629.     if ( RMG.integer )
  630.     {
  631.         char temp[MAX_INFO_STRING];
  632.  
  633.         // start the music
  634.         trap_Cvar_VariableStringBuffer("RMG_music", temp, MAX_QPATH);
  635.         trap_SetConfigstring( CS_MUSIC, temp );
  636.     }
  637.  
  638.     trap_SetConfigstring( CS_VOTE_TIME, "" );
  639. }
  640.  
  641. /*
  642. =================
  643. G_ShutdownGame
  644. =================
  645. */
  646. void G_ShutdownGame( int restart ) 
  647. {
  648.     Com_Printf ("==== ShutdownGame ====\n");
  649.  
  650.     if ( level.logFile ) 
  651.     {
  652.         G_LogPrintf("ShutdownGame:\n" );
  653.         G_LogPrintf("------------------------------------------------------------\n" );
  654.         trap_FS_FCloseFile( level.logFile );
  655.     }
  656.     
  657.     // write all the client session data so we can get it back
  658.     G_WriteSessionData();
  659.  
  660. #ifdef _SOF2_BOTS
  661.     if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) 
  662.     {
  663.         BotAIShutdown( restart );
  664.     }
  665. #endif
  666. }
  667.  
  668.  
  669. #ifndef GAME_HARD_LINKED
  670.  
  671. void QDECL Com_Error ( int level, const char *fmt, ... ) 
  672. {
  673.     va_list        argptr;
  674.     char        text[1024];
  675.  
  676.     va_start (argptr, fmt);
  677.     vsprintf (text, fmt, argptr);
  678.     va_end (argptr);
  679.  
  680.     trap_Error( text );
  681. }
  682.  
  683. void QDECL Com_Printf( const char *msg, ... ) 
  684. {
  685.     va_list        argptr;
  686.     char        text[1024];
  687.  
  688.     va_start (argptr, msg);
  689.     vsprintf (text, msg, argptr);
  690.     va_end (argptr);
  691.  
  692.     trap_Printf( text );
  693. }
  694.  
  695. #endif
  696.  
  697. /*
  698. =============
  699. SortRanks
  700. =============
  701. */
  702. int QDECL SortRanks( const void *a, const void *b ) 
  703. {
  704.     gclient_t    *ca;
  705.     gclient_t    *cb;
  706.  
  707.     ca = &level.clients[*(int *)a];
  708.     cb = &level.clients[*(int *)b];
  709.  
  710.     // sort special clients last
  711.     if ( ca->sess.spectatorState == SPECTATOR_SCOREBOARD ) 
  712.     {
  713.         return 1;
  714.     }
  715.     
  716.     if ( cb->sess.spectatorState == SPECTATOR_SCOREBOARD ) 
  717.     {
  718.         return -1;
  719.     }
  720.  
  721.     // then connecting clients
  722.     if ( ca->pers.connected == CON_CONNECTING ) 
  723.     {
  724.         return 1;
  725.     }
  726.     
  727.     if ( cb->pers.connected == CON_CONNECTING ) 
  728.     {
  729.         return -1;
  730.     }
  731.  
  732.     // then spectators
  733.     if ( ca->sess.team == TEAM_SPECTATOR && cb->sess.team == TEAM_SPECTATOR ) 
  734.     {
  735.         if ( ca->sess.spectatorTime < cb->sess.spectatorTime ) 
  736.         {
  737.             return -1;
  738.         }
  739.         if ( ca->sess.spectatorTime > cb->sess.spectatorTime ) 
  740.         {
  741.             return 1;
  742.         }
  743.         return 0;
  744.     }
  745.     
  746.     if ( ca->sess.team == TEAM_SPECTATOR ) 
  747.     {
  748.         return 1;
  749.     }
  750.     
  751.     if ( cb->sess.team == TEAM_SPECTATOR ) 
  752.     {
  753.         return -1;
  754.     }
  755.  
  756.     // then sort by score
  757.     if ( ca->sess.score > cb->sess.score ) 
  758.     {
  759.         return -1;
  760.     }
  761.     
  762.     if ( ca->sess.score < cb->sess.score ) 
  763.     {
  764.         return 1;
  765.     }
  766.  
  767.     // then sort by kills
  768.     if ( ca->sess.kills > cb->sess.kills ) 
  769.     {
  770.         return -1;
  771.     }
  772.     
  773.     if ( ca->sess.kills < cb->sess.kills ) 
  774.     {
  775.         return 1;
  776.     }
  777.  
  778.     // then sort by deaths
  779.     if ( ca->sess.deaths > cb->sess.deaths ) 
  780.     {
  781.         return -1;
  782.     }
  783.     
  784.     if ( ca->sess.deaths < cb->sess.deaths ) 
  785.     {
  786.         return 1;
  787.     }
  788.     
  789.     return 0;
  790. }
  791.  
  792. /*
  793. ============
  794. CalculateRanks
  795.  
  796. Recalculates the score ranks of all players
  797. This will be called on every client connect, begin, disconnect, death,
  798. and team change.
  799. ============
  800. */
  801. void CalculateRanks( void ) 
  802. {
  803.     int            i;
  804.     int            rank;
  805.     int            score;
  806.     int            newScore;
  807.     gclient_t    *cl;
  808.  
  809.     level.follow1 = -1;
  810.     level.follow2 = -1;
  811.     level.numConnectedClients = 0;
  812.     level.numNonSpectatorClients = 0;
  813.     level.numPlayingClients = 0;
  814.     level.numVotingClients = 0;        // don't count bots
  815.  
  816.     for ( i = 0 ; i < level.maxclients ; i++ ) 
  817.     {
  818.         if ( level.clients[i].pers.connected != CON_DISCONNECTED ) 
  819.         {
  820.             level.sortedClients[level.numConnectedClients] = i;
  821.             level.numConnectedClients++;
  822.  
  823.             if ( level.clients[i].sess.team != TEAM_SPECTATOR ) 
  824.             {
  825.                 level.numNonSpectatorClients++;
  826.             
  827.                 // decide if this should be auto-followed
  828.                 if ( level.clients[i].pers.connected == CON_CONNECTED ) 
  829.                 {
  830.                     level.numPlayingClients++;
  831.                     if ( !(g_entities[i].r.svFlags & SVF_BOT) ) 
  832.                     {
  833.                         level.numVotingClients++;
  834.                     }
  835.                     if ( level.follow1 == -1 ) 
  836.                     {
  837.                         level.follow1 = i;
  838.                     } 
  839.                     else if ( level.follow2 == -1 ) 
  840.                     {
  841.                         level.follow2 = i;
  842.                     }
  843.                 }
  844.             }
  845.         }
  846.     }
  847.  
  848.     qsort( level.sortedClients, level.numConnectedClients, 
  849.            sizeof(level.sortedClients[0]), SortRanks );
  850.  
  851.     // set the rank value for all clients that are connected and not spectators
  852.     if ( level.gametypeData->teams ) 
  853.     {
  854.         int rank;
  855.         if ( level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE] ) 
  856.         {
  857.             rank = 2;
  858.         } 
  859.         else if ( level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE] ) 
  860.         {
  861.             rank = 0;
  862.         } 
  863.         else 
  864.         {
  865.             rank = 1;
  866.         }
  867.  
  868.         // in team games, rank is just the order of the teams, 0=red, 1=blue, 2=tied
  869.         for ( i = 0;  i < level.numConnectedClients; i++ ) 
  870.         {
  871.             cl = &level.clients[ level.sortedClients[i] ];
  872.             cl->ps.persistant[PERS_RANK] = rank;
  873.         }
  874.     } 
  875.     else 
  876.     {    
  877.         rank = -1;
  878.         score = 0;
  879.         for ( i = 0;  i < level.numPlayingClients; i++ ) 
  880.         {
  881.             cl = &level.clients[ level.sortedClients[i] ];
  882.             newScore = cl->sess.score;
  883.             if ( i == 0 || newScore != score ) 
  884.             {
  885.                 rank = i;
  886.                 // assume we aren't tied until the next client is checked
  887.                 level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank;
  888.             } 
  889.             else 
  890.             {
  891.                 // we are tied with the previous client
  892.                 level.clients[ level.sortedClients[i-1] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
  893.                 level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
  894.             }
  895.             score = newScore;
  896.         }
  897.     }
  898.  
  899.  
  900.     // see if it is time to end the level
  901.     CheckExitRules();
  902.  
  903.     // if we are at the intermission, send the new info to everyone
  904.     if ( level.intermissiontime ) 
  905.     {
  906.         SendScoreboardMessageToAllClients();
  907.     }
  908. }
  909.  
  910.  
  911. /*
  912. ========================================================================
  913.  
  914. MAP CHANGING
  915.  
  916. ========================================================================
  917. */
  918.  
  919. /*
  920. ========================
  921. SendScoreboardMessageToAllClients
  922.  
  923. Do this at BeginIntermission time and whenever ranks are recalculated
  924. due to enters/exits/forced team changes
  925. ========================
  926. */
  927. void SendScoreboardMessageToAllClients( void ) {
  928.     int        i;
  929.  
  930.     for ( i = 0 ; i < level.maxclients ; i++ ) {
  931.         if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
  932.             DeathmatchScoreboardMessage( g_entities + i );
  933.         }
  934.     }
  935. }
  936.  
  937. /*
  938. ========================
  939. MoveClientToIntermission
  940.  
  941. When the intermission starts, this will be called for all players.
  942. If a new client connects, this will be called after the spawn function.
  943. ========================
  944. */
  945. void MoveClientToIntermission( gentity_t *ent ) 
  946. {
  947.     // take out of follow mode if needed
  948.     if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) 
  949.     {
  950.         G_StopFollowing( ent );
  951.     }
  952.  
  953.     FindIntermissionPoint ( );
  954.  
  955.     // move to the spot
  956.     VectorCopy( level.intermission_origin, ent->s.origin );
  957.     VectorCopy( level.intermission_origin, ent->r.currentOrigin );
  958.     VectorCopy( level.intermission_origin, ent->client->ps.pvsOrigin );
  959.     VectorCopy( level.intermission_origin, ent->client->ps.origin );
  960.     VectorCopy (level.intermission_angle, ent->client->ps.viewangles);
  961.  
  962.     // Reset some client variables
  963.     ent->client->ps.pm_type          = PM_INTERMISSION;
  964.     ent->client->ps.stats[STAT_GAMETYPE_ITEMS] = 0;
  965.     ent->client->ps.eFlags          = 0;
  966.     ent->s.eFlags                  = 0;
  967.     ent->s.eType                  = ET_GENERAL;
  968.     ent->s.modelindex              = 0;
  969.     ent->s.loopSound              = 0;
  970.     ent->s.event                  = 0;
  971.     ent->r.contents                  = 0;
  972. }
  973.  
  974. /*
  975. ==================
  976. FindIntermissionPoint
  977.  
  978. This is also used for spectator spawns
  979. ==================
  980. */
  981. void FindIntermissionPoint( void ) 
  982. {
  983.     gentity_t    *ent, *target;
  984.     vec3_t        dir;
  985.  
  986.     // find the intermission spot
  987.     ent = G_Find (NULL, FOFS(classname), "info_player_intermission");
  988.     if ( !ent )         
  989.     {    
  990.         gspawn_t* spawn = G_SelectRandomSpawnPoint ( -1 );
  991.         if ( spawn )
  992.         {
  993.             VectorCopy (spawn->origin, level.intermission_origin);
  994.             VectorCopy (spawn->angles, level.intermission_angle);
  995.         }
  996.  
  997.         return;
  998.     } 
  999.  
  1000.     VectorCopy (ent->s.origin, level.intermission_origin);
  1001.     VectorCopy (ent->s.angles, level.intermission_angle);
  1002.  
  1003.     // if it has a target, look towards it
  1004.     if ( ent->target ) 
  1005.     {
  1006.         target = G_PickTarget( ent->target );
  1007.         if ( target ) 
  1008.         {
  1009.             VectorSubtract( target->s.origin, level.intermission_origin, dir );
  1010.             vectoangles( dir, level.intermission_angle );
  1011.         }
  1012.     }
  1013. }
  1014.  
  1015. /*
  1016. ==================
  1017. BeginIntermission
  1018. ==================
  1019. */
  1020. void BeginIntermission( void ) 
  1021. {
  1022.     int            i;
  1023.     gentity_t    *ent;
  1024.  
  1025.     if ( level.intermissiontime ) 
  1026.     {
  1027.         // already active
  1028.         return;        
  1029.     }
  1030.  
  1031.     // Kill any votes
  1032.     level.voteTime = 0;
  1033.     trap_SetConfigstring( CS_VOTE_TIME, "" );
  1034.     
  1035.     level.intermissiontime  = level.time;
  1036.     level.gametypeResetTime = level.time;
  1037.     FindIntermissionPoint();
  1038.  
  1039.     // move all clients to the intermission point
  1040.     for (i=0 ; i< level.maxclients ; i++) 
  1041.     {
  1042.         ent = g_entities + i;
  1043.         if (!ent->inuse)
  1044.         {
  1045.             continue;
  1046.         }
  1047.  
  1048.         // take out of follow mode
  1049.         G_StopFollowing( ent );
  1050.  
  1051.         // Get rid of ghost state
  1052.         G_StopGhosting ( ent );
  1053.  
  1054.         // respawn if dead
  1055.         if ( G_IsClientDead ( ent->client ) ) 
  1056.         {
  1057.             respawn ( ent );
  1058.         }
  1059.  
  1060.         MoveClientToIntermission( ent );
  1061.     }
  1062.  
  1063.     // send the current scoring to all clients
  1064.     SendScoreboardMessageToAllClients();
  1065. }
  1066.  
  1067.  
  1068. /*
  1069. =============
  1070. ExitLevel
  1071.  
  1072. When the intermission has been exited, the server is either killed
  1073. or moved to a new level based on the "nextmap" cvar 
  1074.  
  1075. =============
  1076. */
  1077. void ExitLevel (void) 
  1078. {
  1079.     int            i;
  1080.     gclient_t    *cl;
  1081.  
  1082.     // Next map
  1083.     trap_SendConsoleCommand( EXEC_APPEND, "mapcycle\n" );
  1084.     level.changemap = NULL;
  1085.     level.intermissiontime = 0;
  1086.  
  1087.     // reset all the scores so we don't enter the intermission again
  1088.     level.teamScores[TEAM_RED] = 0;
  1089.     level.teamScores[TEAM_BLUE] = 0;
  1090.     for ( i=0 ; i< g_maxclients.integer ; i++ ) 
  1091.     {
  1092.         cl = level.clients + i;
  1093.         if ( cl->pers.connected != CON_CONNECTED ) 
  1094.         {
  1095.             continue;
  1096.         }
  1097.  
  1098.         cl->sess.score = 0;
  1099.         cl->ps.persistant[PERS_SCORE] = 0;
  1100.     }
  1101.  
  1102.     // we need to do this here before chaning to CON_CONNECTING
  1103.     G_WriteSessionData();
  1104.  
  1105.     // change all client states to connecting, so the early players into the
  1106.     // next level will know the others aren't done reconnecting
  1107.     for (i=0 ; i< g_maxclients.integer ; i++) 
  1108.     {
  1109.         if ( level.clients[i].pers.connected == CON_CONNECTED ) 
  1110.         {
  1111.             level.clients[i].pers.connected = CON_CONNECTING;
  1112.         }
  1113.     }
  1114.  
  1115. }
  1116.  
  1117. /*
  1118. =================
  1119. G_LogPrintf
  1120.  
  1121. Print to the logfile with a time stamp if it is open
  1122. =================
  1123. */
  1124. void QDECL G_LogPrintf( const char *fmt, ... ) {
  1125.     va_list        argptr;
  1126.     char        string[1024];
  1127.     int            min, tens, sec;
  1128.  
  1129.     sec = level.time / 1000;
  1130.  
  1131.     min = sec / 60;
  1132.     sec -= min * 60;
  1133.     tens = sec / 10;
  1134.     sec -= tens * 10;
  1135.  
  1136.     Com_sprintf( string, sizeof(string), "%4i:%i%i ", min, tens, sec );
  1137.  
  1138.     va_start( argptr, fmt );
  1139.     vsprintf( string +8 , fmt,argptr );
  1140.     va_end( argptr );
  1141.  
  1142. #ifndef _DEBUG
  1143.     if ( g_dedicated.integer ) {
  1144. #endif
  1145.         Com_Printf( "%s", string + 8 );
  1146. #ifndef _DEBUG
  1147.     }
  1148. #endif
  1149.  
  1150.     if ( !level.logFile ) {
  1151.         return;
  1152.     }
  1153.  
  1154.     trap_FS_Write( string, strlen( string ), level.logFile );
  1155. }
  1156.  
  1157. /*
  1158. ================
  1159. LogExit
  1160.  
  1161. Append information about this game to the log file
  1162. ================
  1163. */
  1164. void LogExit( const char *string ) 
  1165. {
  1166.     int                i;
  1167.     int                numSorted;
  1168.     gclient_t        *cl;
  1169.  
  1170.     G_LogPrintf( "Exit: %s\n", string );
  1171.  
  1172.     level.intermissionQueued = level.time;
  1173.  
  1174.     // this will keep the clients from playing any voice sounds
  1175.     // that will get cut off when the queued intermission starts
  1176.     trap_SetConfigstring( CS_INTERMISSION, "1" );
  1177.  
  1178.     // don't send more than 32 scores (FIXME?)
  1179.     numSorted = level.numConnectedClients;
  1180.     if ( numSorted > 32 ) 
  1181.     {
  1182.         numSorted = 32;
  1183.     }
  1184.  
  1185.     if ( level.gametypeData->teams ) 
  1186.     {
  1187.         G_LogPrintf( "red:%i  blue:%i\n", level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE] );
  1188.     }
  1189.  
  1190.     for (i=0 ; i < numSorted ; i++) 
  1191.     {
  1192.         int    ping;
  1193.  
  1194.         cl = &level.clients[level.sortedClients[i]];
  1195.  
  1196.         if ( cl->sess.team == TEAM_SPECTATOR ) 
  1197.         {
  1198.             continue;
  1199.         }
  1200.  
  1201.         if ( cl->pers.connected == CON_CONNECTING ) 
  1202.         {
  1203.             continue;
  1204.         }
  1205.  
  1206.         ping = cl->ps.ping < 999 ? cl->ps.ping : 999;
  1207.  
  1208.         G_LogPrintf( "score: %i  ping: %i  client: %i %s\n", cl->sess.score, ping, level.sortedClients[i],    cl->pers.netname );
  1209.     }
  1210. }
  1211.  
  1212.  
  1213. /*
  1214. =================
  1215. CheckIntermissionExit
  1216.  
  1217. The level will stay at the intermission for a minimum of 5 seconds
  1218. If all players wish to continue, the level will then exit.
  1219. If one or more players have not acknowledged the continue, the game will
  1220. wait 10 seconds before going on.
  1221. =================
  1222. */
  1223. void CheckIntermissionExit( void ) 
  1224. {
  1225.     int            ready, notReady;
  1226.     int            i;
  1227.     gclient_t    *cl;
  1228.     int            readyMask;
  1229.  
  1230.     // see which players are ready
  1231.     ready = 0;
  1232.     notReady = 0;
  1233.     readyMask = 0;
  1234.     for (i=0 ; i< g_maxclients.integer ; i++) {
  1235.         cl = level.clients + i;
  1236.         if ( cl->pers.connected != CON_CONNECTED ) {
  1237.             continue;
  1238.         }
  1239.         if ( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) {
  1240.             continue;
  1241.         }
  1242.  
  1243.         if ( cl->readyToExit ) {
  1244.             ready++;
  1245.             if ( i < 16 ) {
  1246.                 readyMask |= 1 << i;
  1247.             }
  1248.         } else {
  1249.             notReady++;
  1250.         }
  1251.     }
  1252.  
  1253.     // copy the readyMask to each player's stats so
  1254.     // it can be displayed on the scoreboard
  1255.     for (i=0 ; i< g_maxclients.integer ; i++) {
  1256.         cl = level.clients + i;
  1257.         if ( cl->pers.connected != CON_CONNECTED ) {
  1258.             continue;
  1259.         }
  1260.         cl->ps.stats[STAT_CLIENTS_READY] = readyMask;
  1261.     }
  1262.  
  1263.     // never exit in less than five seconds
  1264.     if ( level.time < level.intermissiontime + 5000 ) {
  1265.         return;
  1266.     }
  1267.  
  1268.     // if nobody wants to go, clear timer
  1269.     if ( !ready ) {
  1270.         level.readyToExit = qfalse;
  1271.         return;
  1272.     }
  1273.  
  1274.     // if everyone wants to go, go now
  1275.     if ( !notReady ) {
  1276.         ExitLevel();
  1277.         return;
  1278.     }
  1279.  
  1280.     // the first person to ready starts the ten second timeout
  1281.     if ( !level.readyToExit ) {
  1282.         level.readyToExit = qtrue;
  1283.         level.exitTime = level.time;
  1284.     }
  1285.  
  1286.     // if we have waited ten seconds since at least one player
  1287.     // wanted to exit, go ahead
  1288.     if ( level.time < level.exitTime + 10000 ) {
  1289.         return;
  1290.     }
  1291.  
  1292.     ExitLevel();
  1293. }
  1294.  
  1295. /*
  1296. =============
  1297. ScoreIsTied
  1298. =============
  1299. */
  1300. qboolean ScoreIsTied( void ) 
  1301. {
  1302.     int    a;
  1303.     int b;
  1304.  
  1305.     if ( level.numPlayingClients < 2 ) 
  1306.     {
  1307.         return qfalse;
  1308.     }
  1309.     
  1310.     if ( level.gametypeData->teams ) 
  1311.     {
  1312.         return level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE];
  1313.     }
  1314.  
  1315.     a = level.clients[level.sortedClients[0]].sess.score;
  1316.     b = level.clients[level.sortedClients[1]].sess.score;
  1317.  
  1318.     return a == b;
  1319. }
  1320.  
  1321. /*
  1322. =================
  1323. CheckExitRules
  1324.  
  1325. There will be a delay between the time the exit is qualified for
  1326. and the time everyone is moved to the intermission spot, so you
  1327. can see the last frag.
  1328. =================
  1329. */
  1330. void CheckExitRules( void ) 
  1331. {
  1332.      int            i;
  1333.     gclient_t    *cl;
  1334.  
  1335.     // if at the intermission, wait for all non-bots to
  1336.     // signal ready, then go to next level
  1337.     if ( level.intermissiontime ) 
  1338.     {
  1339.         CheckIntermissionExit ();
  1340.         return;
  1341.     }
  1342.  
  1343.     if ( level.intermissionQueued ) 
  1344.     {
  1345.         int time = INTERMISSION_DELAY_TIME;
  1346.         if ( level.time - level.intermissionQueued >= time ) 
  1347.         {
  1348.             level.intermissionQueued = 0;
  1349.             BeginIntermission();
  1350.         }
  1351.  
  1352.         return;
  1353.     }
  1354.  
  1355.     // check for sudden death
  1356.     if ( g_suddenDeath.integer && ScoreIsTied() ) 
  1357.     {
  1358.         // always wait for sudden death
  1359.         return;
  1360.     }
  1361.  
  1362.     // Check to see if the timelimit was hit
  1363.     if ( g_timelimit.integer && !level.warmupTime ) 
  1364.     {
  1365.         if ( level.time - level.startTime >= (g_timelimit.integer + level.timeExtension)*60000 ) 
  1366.         {
  1367.             gentity_t* tent;
  1368.             tent = G_TempEntity( vec3_origin, EV_GAME_OVER );
  1369.             tent->s.eventParm = GAME_OVER_TIMELIMIT;
  1370.             tent->r.svFlags = SVF_BROADCAST;    
  1371.  
  1372.             LogExit( "Timelimit hit." );
  1373.             return;
  1374.         }
  1375.     }
  1376.  
  1377.     // Check to see if the score was hit
  1378.     if ( g_scorelimit.integer ) 
  1379.     {
  1380.         if ( level.gametypeData->teams )
  1381.         {
  1382.             if ( level.teamScores[TEAM_RED] >= g_scorelimit.integer ) 
  1383.             {
  1384.                 gentity_t* tent;
  1385.                 tent = G_TempEntity( vec3_origin, EV_GAME_OVER );
  1386.                 tent->s.eventParm = GAME_OVER_SCORELIMIT;
  1387.                 tent->r.svFlags = SVF_BROADCAST;    
  1388.                 tent->s.otherEntityNum = TEAM_RED;
  1389.  
  1390.                 LogExit( "Red team hit the score limit." );
  1391.                 return;
  1392.             }
  1393.  
  1394.             if ( level.teamScores[TEAM_BLUE] >= g_scorelimit.integer ) 
  1395.             {
  1396.                 gentity_t* tent;
  1397.                 tent = G_TempEntity( vec3_origin, EV_GAME_OVER );
  1398.                 tent->s.eventParm = GAME_OVER_SCORELIMIT;
  1399.                 tent->r.svFlags = SVF_BROADCAST;    
  1400.                 tent->s.otherEntityNum = TEAM_BLUE;
  1401.  
  1402.                 LogExit( "Blue team hit the score limit." );
  1403.                 return;
  1404.             }
  1405.         }
  1406.         else
  1407.         {
  1408.             // Check to see if any of the clients scores have crossed the scorelimit
  1409.             for ( i = 0 ; i < level.numConnectedClients ; i++ ) 
  1410.             {
  1411.                 cl = g_entities[level.sortedClients[i]].client;
  1412.  
  1413.                 if ( cl->pers.connected != CON_CONNECTED )
  1414.                 {
  1415.                     continue;
  1416.                 }
  1417.  
  1418.                 if ( cl->sess.team != TEAM_FREE ) 
  1419.                 {
  1420.                     continue;
  1421.                 }
  1422.  
  1423.                 if ( cl->sess.score >= g_scorelimit.integer ) 
  1424.                 {
  1425.                     gentity_t* tent;
  1426.                     tent = G_TempEntity( vec3_origin, EV_GAME_OVER );
  1427.                     tent->s.eventParm = GAME_OVER_SCORELIMIT;
  1428.                     tent->r.svFlags = SVF_BROADCAST;    
  1429.                     tent->s.otherEntityNum = level.sortedClients[i];
  1430.  
  1431.                     LogExit( "Scorelimit hit." );
  1432.                     return;
  1433.                 }
  1434.             }
  1435.         }
  1436.     }
  1437. }
  1438.  
  1439. /*
  1440. =============
  1441. CheckWarmup
  1442. =============
  1443. */
  1444. void CheckWarmup ( void ) 
  1445. {
  1446.     int            counts[TEAM_NUM_TEAMS];
  1447.     qboolean    notEnough = qfalse;
  1448.  
  1449.     // check because we run 3 game frames before calling Connect and/or ClientBegin
  1450.     // for clients on a map_restart
  1451.     if ( level.numPlayingClients == 0 ) 
  1452.     {
  1453.         return;
  1454.     }
  1455.  
  1456.     if ( !level.warmupTime  ) 
  1457.     {
  1458.         return;
  1459.     }
  1460.  
  1461.     if ( level.gametypeData->teams ) 
  1462.     {
  1463.         counts[TEAM_BLUE] = TeamCount( -1, TEAM_BLUE, NULL );
  1464.         counts[TEAM_RED] = TeamCount( -1, TEAM_RED, NULL );
  1465.  
  1466.         if (counts[TEAM_RED] < 1 || counts[TEAM_BLUE] < 1) 
  1467.         {
  1468.             notEnough = qtrue;
  1469.         }
  1470.     } 
  1471.     else if ( level.numPlayingClients < 2 ) 
  1472.     {
  1473.         notEnough = qtrue;
  1474.     }
  1475.  
  1476.     if ( notEnough ) 
  1477.     {
  1478.         if ( level.warmupTime != -1 ) 
  1479.         {
  1480.             level.warmupTime = -1;
  1481.             trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
  1482.             G_LogPrintf( "Warmup:\n" );
  1483.         }
  1484.         
  1485.         return; // still waiting for team members
  1486.     }
  1487.  
  1488.     if ( level.warmupTime == 0 ) 
  1489.     {
  1490.         return;
  1491.     }
  1492.  
  1493.     // if the warmup is changed at the console, restart it
  1494.     if ( g_warmup.modificationCount != level.warmupModificationCount ) 
  1495.     {
  1496.         level.warmupModificationCount = g_warmup.modificationCount;
  1497.         level.warmupTime = -1;
  1498.     }
  1499.  
  1500.     // if all players have arrived, start the countdown
  1501.     if ( level.warmupTime < 0 ) 
  1502.     {
  1503.         // fudge by -1 to account for extra delays
  1504.         level.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;
  1505.         trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
  1506.         return;
  1507.     }
  1508.  
  1509.     // if the warmup time has counted down, restart
  1510.     if ( level.time > level.warmupTime ) 
  1511.     {
  1512.         level.warmupTime += 10000;
  1513.         trap_Cvar_Set( "g_restarted", "1" );
  1514.         trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
  1515.         level.restarted = qtrue;
  1516.         return;
  1517.     }
  1518. }
  1519.  
  1520. /*
  1521. ==================
  1522. CheckVote
  1523. ==================
  1524. */
  1525. void CheckVote( void ) 
  1526. {
  1527.     if ( level.voteExecuteTime && level.voteExecuteTime < level.time ) 
  1528.     {
  1529.         level.voteExecuteTime = 0;
  1530.         trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.voteString ) );
  1531.     }
  1532.  
  1533.     if ( !level.voteTime )
  1534.     {
  1535.         return;
  1536.     }
  1537.  
  1538.     // Update the needed clients
  1539.     trap_SetConfigstring ( CS_VOTE_NEEDED, va("%i", (level.numVotingClients / 2) + 1 ) );
  1540.  
  1541.     if ( level.time - level.voteTime >= g_voteDuration.integer*1000 ) 
  1542.     {
  1543.         trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
  1544.         level.clients[level.voteClient].voteDelayTime = level.time + g_failedVoteDelay.integer * 60000;
  1545.     } 
  1546.     else 
  1547.     {
  1548.         if ( level.voteYes > level.numVotingClients/2 ) 
  1549.         {
  1550.             // execute the command, then remove the vote
  1551.             trap_SendServerCommand( -1, "print \"Vote passed.\n\"" );
  1552.             level.voteExecuteTime = level.time + 3000;
  1553.         } 
  1554.         else if ( level.voteNo >= level.numVotingClients/2 ) 
  1555.         {
  1556.             // same behavior as a timeout
  1557.             trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
  1558.             level.clients[level.voteClient].voteDelayTime = level.time + g_failedVoteDelay.integer * 60000;
  1559.         } 
  1560.         else 
  1561.         {
  1562.             // still waiting for a majority
  1563.             return;
  1564.         }
  1565.     }
  1566.  
  1567.     level.voteTime = 0;
  1568.     trap_SetConfigstring( CS_VOTE_TIME, "" );
  1569. }
  1570.  
  1571. /*
  1572. ==================
  1573. PrintTeam
  1574. ==================
  1575. */
  1576. void PrintTeam(int team, char *message) 
  1577. {
  1578.     int i;
  1579.  
  1580.     for ( i = 0 ; i < level.maxclients ; i++ ) 
  1581.     {
  1582.         if (level.clients[i].sess.team != team)
  1583.         {
  1584.             continue;
  1585.         }
  1586.  
  1587.         trap_SendServerCommand( i, message );
  1588.     }
  1589. }
  1590.  
  1591. /*
  1592. ==================
  1593. CheckCvars
  1594. ==================
  1595. */
  1596. void CheckCvars( void ) 
  1597. {
  1598.     static int lastMod = -1;
  1599.  
  1600.     if ( g_password.modificationCount != lastMod ) 
  1601.     {
  1602.         lastMod = g_password.modificationCount;
  1603.         if ( *g_password.string && Q_stricmp( g_password.string, "none" ) ) 
  1604.         {
  1605.             trap_Cvar_Set( "g_needpass", "1" );
  1606.         } else 
  1607.         {
  1608.             trap_Cvar_Set( "g_needpass", "0" );
  1609.         }
  1610.     }
  1611. }
  1612.  
  1613. /*
  1614. =============
  1615. G_RunThink
  1616.  
  1617. Runs thinking code for this frame if necessary
  1618. =============
  1619. */
  1620. void G_RunThink (gentity_t *ent) 
  1621. {
  1622.     float    thinktime;
  1623.  
  1624.     thinktime = ent->nextthink;
  1625.  
  1626.     if (thinktime <= 0) 
  1627.     {
  1628.         return;
  1629.     }
  1630.     if (thinktime > level.time) 
  1631.     {
  1632.         return;
  1633.     }
  1634.     
  1635.     ent->nextthink = 0;
  1636.     if (!ent->think) 
  1637.     {
  1638.         Com_Error ( ERR_FATAL, "NULL ent->think");
  1639.     }
  1640.     ent->think (ent);
  1641. }
  1642.  
  1643. /*
  1644. ================
  1645. G_RunFrame
  1646.  
  1647. Advances the non-player objects in the world
  1648. ================
  1649. */
  1650. void G_RunFrame( int levelTime ) 
  1651. {
  1652.     int            i;
  1653.     gentity_t    *ent;
  1654.     int            msec;
  1655.  
  1656.     //NT - store the time the frame started
  1657.     level.frameStartTime = trap_Milliseconds();
  1658.  
  1659.     // if we are waiting for the level to restart, do nothing
  1660.     if ( level.restarted ) 
  1661.     {
  1662.         return;
  1663.     }
  1664.  
  1665.     level.framenum++;
  1666.     level.previousTime = level.time;
  1667.     level.time = levelTime;
  1668.     msec = level.time - level.previousTime;
  1669.  
  1670.     // get any cvar changes
  1671.     G_UpdateCvars();
  1672.  
  1673.     // go through all allocated objects
  1674.     ent = &g_entities[0];
  1675.     for (i=0 ; i<level.num_entities ; i++, ent++) 
  1676.     {
  1677.         if ( !ent->inuse ) 
  1678.         {
  1679.             continue;
  1680.         }
  1681.  
  1682.         // clear events that are too old
  1683.         if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) 
  1684.         {
  1685.             if ( ent->s.event ) 
  1686.             {
  1687.                 ent->s.event = 0;    // &= EV_EVENT_BITS;
  1688.                 if ( ent->client ) 
  1689.                 {
  1690.                     ent->client->ps.externalEvent = 0;
  1691.                     // predicted events should never be set to zero
  1692.                     //ent->client->ps.events[0] = 0;
  1693.                     //ent->client->ps.events[1] = 0;
  1694.                 }
  1695.             }
  1696.             
  1697.             if ( ent->freeAfterEvent ) 
  1698.             {
  1699.                 // tempEntities or dropped items completely go away after their event
  1700.                 G_FreeEntity( ent );
  1701.                 continue;
  1702.             } 
  1703.             else if ( ent->unlinkAfterEvent ) 
  1704.             {
  1705.                 // items that will respawn will hide themselves after their pickup event
  1706.                 ent->unlinkAfterEvent = qfalse;
  1707.                 trap_UnlinkEntity( ent );
  1708.             }
  1709.         }
  1710.  
  1711.         // temporary entities don't think
  1712.         if ( ent->freeAfterEvent ) 
  1713.         {
  1714.             continue;
  1715.         }
  1716.  
  1717.         if ( !ent->r.linked && ent->neverFree ) 
  1718.         {
  1719.             continue;
  1720.         }
  1721.  
  1722.         if ( ent->s.eType == ET_MISSILE ) 
  1723.         {
  1724.             G_RunMissile( ent );
  1725.             continue;
  1726.         }
  1727.  
  1728.         if ( ent->s.eType == ET_ITEM || ent->physicsObject ) 
  1729.         {
  1730.             G_RunItem( ent );
  1731.             continue;
  1732.         }
  1733.  
  1734.         if ( ent->s.eType == ET_MOVER ) 
  1735.         {
  1736.             G_RunMover( ent );
  1737.             continue;
  1738.         }
  1739.  
  1740.         if ( i < MAX_CLIENTS ) 
  1741.         {
  1742.             G_CheckClientTimeouts ( ent );
  1743.             G_RunClient( ent );
  1744.             G_CheckClientTeamkill ( ent );
  1745.             continue;
  1746.         }
  1747.  
  1748.         G_RunThink( ent );
  1749.     }
  1750.  
  1751.     // perform final fixups on the players
  1752.     ent = &g_entities[0];
  1753.     for (i=0 ; i < level.maxclients ; i++, ent++ ) 
  1754.     {
  1755.         if ( ent->inuse ) 
  1756.         {
  1757.             ClientEndFrame( ent );
  1758.         }
  1759.     }
  1760.  
  1761.     // Check warmup rules
  1762.     CheckWarmup();
  1763.  
  1764.     // see if it is time to end the level
  1765.     CheckExitRules();
  1766.  
  1767.     // Update gametype stuff
  1768.     CheckGametype ();        
  1769.  
  1770.     trap_GT_RunFrame ( level.time );
  1771.  
  1772.     // cancel vote if timed out
  1773.     CheckVote();
  1774.  
  1775.     // for tracking changes
  1776.     CheckCvars();
  1777.  
  1778.     if (g_listEntity.integer) 
  1779.     {
  1780.         for (i = 0; i < MAX_GENTITIES; i++) 
  1781.         {
  1782.             Com_Printf("%4i: %s\n", i, g_entities[i].classname);
  1783.         }
  1784.         trap_Cvar_Set("g_listEntity", "0");
  1785.     }
  1786. }
  1787.  
  1788. void G_InitGhoul ( void )
  1789. {
  1790.     G_InitHitModels ( );
  1791. }
  1792.  
  1793. void G_ShutdownGhoul ( void )
  1794. {
  1795.     if ( !level.serverGhoul2 )
  1796.     {
  1797.         return;
  1798.     }
  1799.  
  1800.     trap_G2API_CleanGhoul2Models ( &level.serverGhoul2 );
  1801.     level.serverGhoul2 = NULL;
  1802. }
  1803.  
  1804.